package com.heng.plugin

import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes

class LocationClassVisitor(classVisitor: ClassVisitor) : ClassVisitor(Opcodes.ASM5, classVisitor) {

    override fun visitMethod(
        access: Int,
        name: String?,
        descriptor: String?,
        signature: String?,
        exceptions: Array<out String>?
    ): MethodVisitor {
        val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
        if (name == "getLocation") {
            return LocationMethodVisitor(mv)
        }
        return mv
    }
}

class LocationMethodVisitor(methodVisitor: MethodVisitor) : MethodVisitor(Opcodes.ASM5, methodVisitor) {

    override fun visitCode() {
        super.visitCode()

        // 创建MyLocation对象
        mv.visitTypeInsn(Opcodes.NEW, "com/heng/application/mocklocation/widget/MyLocation")
        mv.visitInsn(Opcodes.DUP)
        mv.visitMethodInsn(
            Opcodes.INVOKESPECIAL,
            "com/heng/application/mocklocation/widget/MyLocation",
            "<init>",
            "()V",
            false
        )
        mv.visitVarInsn(Opcodes.ASTORE, 1)

        // 获取SharedPreferences
        mv.visitFieldInsn(
            Opcodes.GETSTATIC,
            "com/heng/application/mocklocation/widget/MockLocation",
            "applicationContext",
            "Landroid/content/Context;"
        )
        mv.visitLdcInsn("location_prefs")
        mv.visitInsn(Opcodes.ICONST_0)
        mv.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "android/content/Context",
            "getSharedPreferences",
            "(Ljava/lang/String;I)Landroid/content/SharedPreferences;",
            false
        )
        mv.visitVarInsn(Opcodes.ASTORE, 2)

        // 获取mock_switch状态
        mv.visitVarInsn(Opcodes.ALOAD, 2)
        mv.visitLdcInsn("mock_switch")
        mv.visitInsn(Opcodes.ICONST_0)
        mv.visitMethodInsn(
            Opcodes.INVOKEINTERFACE,
            "android/content/SharedPreferences",
            "getBoolean",
            "(Ljava/lang/String;Z)Z",
            true
        )

        // 创建标签用于跳转
        val label = Label()
        mv.visitJumpInsn(Opcodes.IFEQ, label)

        // 如果开关打开，获取保存的值
        mv.visitVarInsn(Opcodes.ALOAD, 2)
        mv.visitLdcInsn("latitude")
        mv.visitLdcInsn("0.0")
        mv.visitMethodInsn(
            Opcodes.INVOKEINTERFACE,
            "android/content/SharedPreferences",
            "getString",
            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
            true
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "parseDouble",
            "(Ljava/lang/String;)D",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "valueOf",
            "(D)Ljava/lang/Double;",
            false
        )
        mv.visitVarInsn(Opcodes.ASTORE, 3)

        mv.visitVarInsn(Opcodes.ALOAD, 2)
        mv.visitLdcInsn("longitude")
        mv.visitLdcInsn("0.0")
        mv.visitMethodInsn(
            Opcodes.INVOKEINTERFACE,
            "android/content/SharedPreferences",
            "getString",
            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
            true
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "parseDouble",
            "(Ljava/lang/String;)D",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "valueOf",
            "(D)Ljava/lang/Double;",
            false
        )
        mv.visitVarInsn(Opcodes.ASTORE, 4)

        // 设置保存的值
        mv.visitVarInsn(Opcodes.ALOAD, 1)
        mv.visitVarInsn(Opcodes.ALOAD, 3)
        mv.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "com/heng/application/mocklocation/widget/MyLocation",
            "setLatitude",
            "(Ljava/lang/Double;)V",
            false
        )

        mv.visitVarInsn(Opcodes.ALOAD, 1)
        mv.visitVarInsn(Opcodes.ALOAD, 4)
        mv.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "com/heng/application/mocklocation/widget/MyLocation",
            "setLongitude",
            "(Ljava/lang/Double;)V",
            false
        )
        // 创建结束标签
        val endLabel = Label()
        mv.visitJumpInsn(Opcodes.GOTO, endLabel)

        // 开关关闭时设置默认值
        mv.visitLabel(label)
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null)
        mv.visitVarInsn(Opcodes.ALOAD, 1)
        mv.visitLdcInsn("111.1")
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "parseDouble",
            "(Ljava/lang/String;)D",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "valueOf",
            "(D)Ljava/lang/Double;",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "com/heng/application/mocklocation/widget/MyLocation",
            "setLatitude",
            "(Ljava/lang/Double;)V",
            false
        )

        mv.visitVarInsn(Opcodes.ALOAD, 1)
        mv.visitLdcInsn("222.2")
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "parseDouble",
            "(Ljava/lang/String;)D",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKESTATIC,
            "java/lang/Double",
            "valueOf",
            "(D)Ljava/lang/Double;",
            false
        )
        mv.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            "com/heng/application/mocklocation/widget/MyLocation",
            "setLongitude",
            "(Ljava/lang/Double;)V",
            false
        )

        // 设置结束标签
        mv.visitLabel(endLabel)
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null)

        // 返回结果
        mv.visitVarInsn(Opcodes.ALOAD, 1)
        mv.visitInsn(Opcodes.ARETURN)
    }
}